# -*- coding: utf-8 -*-
"""
Created on Mon May 15 09:07:06 2017

@author: GangTimes
"""
import numpy
import dual_demo
def model_fun(theta,x):
    '''
    这是模型函数
    theta:系数 matrix[mx1]  m为变量数 
    b:系数 matrix[1x1]
    x:自变量 matrix[nxm]  n为样本数   m为变量数 包含x=1
    return: matrix[nx1]
    '''
    rows=x.shape[0]
    temp=(theta.T*x.T).T
    yval=[]
    
    if rows==1:
        yval.append(_sign_fun(temp[0,0],0))
        return numpy.matrix(yval)
    elif rows>1:
        for index in range(rows):
            yval.append(_sign_fun(temp[index,0],0))
        return numpy.matrix(yval).T
		
def _sign_fun(x,b):
    '''
    sign函数  符号判别函数
    x:自变量 
    b:参考变量
    '''
    if x>=b:
        return 1
    else:
        return -1
			
def gram_matrix(x):
    '''
    Gram矩阵的计算  
    x的内积
    x:自变量 matrix[nxm] 包含最后一列
    return: matrix[nxn]
    '''
    
    return numpy.dot(x,x.T)
    
def loss_fun(gram,y,alpha):
    '''
    损失函数
    gram: Gram 矩阵  matrix[nxn]
    alpha:积累次数 
    index:索引  默认计算损失函数和  如果有索引  计算索引项的损失函数
    '''
    rows=y.shape[0]
    loss_sum=0

    for index in range(rows):
        temp=fun_distance(gram,y,alpha,index)
        if temp>0:
            loss_sum=loss_sum+temp
        
    return loss_sum
    
def fun_distance(gram,y,alpha,index):
    '''
     函数间隔计算       
     theta:系数 matrix[mx1]
    x:自变量 matrix[1xm] 第一列为1
    y:因变量 matrix[1x1]
    return: 函数间隔 matrix[1x1]
    '''
    yi=y[index,0]
    gi=gram[:,index]
    
    return -1*yi*numpy.sum(numpy.multiply(numpy.multiply(alpha,y),gi))
def theta_fun(alpha,x,y):
    '''
    系数计算函数
    反解系数
    '''    
    return numpy.sum(numpy.multiply(numpy.multiply(alpha,y),x),0).T

def dual(x,y):
    '''
    PLA对偶算法主程序
    x: matrix[nxm] m参数个数  n为样本数
    y: matrix[nx1] 
    '''
    rows=x.shape[0]
    alpha=numpy.matrix(numpy.zeros((rows,1)))
    step=1
    index=0
    flag=0
    loss=[]
    gram=gram_matrix(x)
    while(True):
        
        if index==rows:
            index=0
        if flag==rows:
            break
        
        loss.append(loss_fun(gram,y,alpha))
        dist=fun_distance(gram,y,alpha,index)
        flag=flag+1
        print(dist)
        if dist>=0:
            alpha[index,0]=alpha[index,0]+1
            flag=0
        
        index=index+step
    
    theta=theta_fun(alpha,x,y)
    
    return [theta,loss]

if __name__=="__main__":
    dual_demo.dual_demo()
